﻿using Microsoft.AspNetCore.Authorization;
using Microsoft.EntityFrameworkCore;
using Qianke.Core.Common.Dto;
using Qianke.Core.Common.Interface;
using System.Linq.Dynamic.Core;
using Volo.Abp.Auditing;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.EntityFrameworkCore;

namespace Qianke.Core.Saas.Application.BaseService
{

    using Common;

    [Authorize("MastLogin")]
    public class SaasBaseService<TEntity, TPrimaryKey, TGetModelOutputDto, TAddOrUpdateInputDto, TGetPageInputDto, TGetPageOutputDto, TDbContext> : BusinessService<TDbContext>
        where TEntity : Entity<TPrimaryKey>
        where TGetPageInputDto : PageDto
        where TDbContext : IEfCoreDbContext
    {
        /// <summary>
        /// 仓储
        /// </summary>
        protected IRepository<TEntity, TPrimaryKey> _repository => LazyServiceProvider.LazyGetRequiredService<IRepository<TEntity, TPrimaryKey>>();

        /// <summary>
        /// 添加或更新前置事件
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        protected virtual Task OnAddOrUpdateBefore(TEntity model, TAddOrUpdateInputDto dto) => Task.CompletedTask;

        /// <summary>
        /// //添加或更新后置事件
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        protected virtual Task OnAddOrUpdateAfter(TEntity model, TAddOrUpdateInputDto dto) => Task.CompletedTask;


        public Task<TGetModelOutputDto> SaveModel(TAddOrUpdateInputDto dto) => AddOrUpdate(dto);

        /// <summary>
        /// 添加或更新数据
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public virtual async Task<TGetModelOutputDto> AddOrUpdate(TAddOrUpdateInputDto dto)
        {
            var model = MapTo<TEntity>(dto);
            if (model.Id == null || model.Id.Equals(default(TPrimaryKey)))
            {
                await OnAddOrUpdateBefore(model, dto);
                if (model is IHasOrganId modelOrgan)
                    modelOrgan.OrganId = tokenModel.OrganId;
                await _repository.InsertAsync(model);
            }
            else
            {
                model = await _repository.FindAsync(model.Id, true);
                if (model == null)
                    throw new Exception("数据不存在");
                await OnAddOrUpdateBefore(model, dto);
                ObjectMapper.Map(dto, model);
                await _repository.UpdateAsync(model);
            }
            await OnAddOrUpdateAfter(model, dto);
            //更新缓存名称
            if (model is IHasName)
            {
                var db = await GetDB();
                await _repository.UpdateCacheName(model);
            }
            return MapTo<TGetModelOutputDto>(model);
        }

        /// <summary>
        /// 根据ID查询详细信息
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public virtual async Task<TGetModelOutputDto> GetModel(EntityInputDto<TPrimaryKey> entity)
        {
            var model = await _repository.FindAsync(entity.Id);
            if (model == null)
                throw new Exception("数据不存在");
            return MapTo<TGetModelOutputDto>(model);
        }

        /// <summary>
        /// 获取分页数据 过滤函数
        /// </summary>
        /// <param name="queryData"></param>
        /// <param name="dto"></param>
        /// <returns></returns>
        protected virtual IQueryable<TEntity> GetPageFilter(IQueryable<TEntity> queryData, TGetPageInputDto dto)
        {
            return queryData;
        }

        /// <summary>
        /// 获取分页数据 排序函数
        /// </summary>
        /// <param name="queryData"></param>
        /// <param name="dto"></param>
        /// <returns></returns>
        protected virtual IQueryable<TEntity> GetPageOrderBy(IQueryable<TEntity> queryData, TGetPageInputDto dto)
        {
            if (typeof(IHasCreationTime).IsAssignableFrom(typeof(TEntity)))
                return queryData.OrderByDescending(u => ((IHasCreationTime)u).CreationTime);
            else
                return queryData.OrderByDescending(u => u.Id);
        }

        protected virtual async Task<List<TGetPageOutputDto>> OnGetPageOutput(List<TEntity> dataList, TGetPageInputDto dto)
        {
            await Task.CompletedTask;
            return MapTo<TGetPageOutputDto>(dataList);
        }

        /// <summary>
        /// 获取分页数据 输出函数
        /// </summary>
        /// <param name="queryData"></param>
        /// <param name="dto"></param>
        /// <returns></returns>
        protected virtual async Task<PageOutputDto<TGetPageOutputDto>> GetPageOutput(IQueryable<TEntity> queryData, TGetPageInputDto dto)
        {
            var pageResult = queryData.PageResult(dto.PageIndex, dto.PageSize);
            var dataList = await pageResult.Queryable.ToListAsync();
            var result = new PageOutputDto<TGetPageOutputDto>()
            {
                data = await OnGetPageOutput(dataList, dto),
                totalCount = pageResult.RowCount,
            };
            return result;
        }

        /// <summary>
        /// 分页查询数据
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>

        public virtual async Task<PageOutputDto<TGetPageOutputDto>> GetPage(TGetPageInputDto dto)
        {
            var queryData = await _repository.GetQueryableAsync();
            queryData = GetPageFilter(queryData, dto);
            queryData = GetPageOrderBy(queryData, dto);
            return await GetPageOutput(queryData, dto);
        }

        /// <summary>
        /// 删除前置事件
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        protected virtual Task OnDeleteBefore(TEntity model) => Task.CompletedTask;

        /// <summary>
        /// 删除后置事件
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        protected virtual Task OnDeleteAfter(TEntity model) => Task.CompletedTask;

        /// <summary>
        /// 删除数据
        /// </summary>
        /// <param name="entityDto"></param>
        /// <returns></returns>
        public virtual async Task<TPrimaryKey> Delete(EntityInputDto<TPrimaryKey> entityDto)
        {
            var model = await _repository.FindAsync(entityDto.Id);
            if (model != null)
            {
                await OnDeleteBefore(model);
                await _repository.DeleteAsync(model);
                await OnDeleteAfter(model);
            }
            return entityDto.Id;
        }
    }
}
